﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Reflection;
using PublicCommon;

namespace NHibernateHelper
{
    public class Convert
    {
        /// <summary>
        /// Ilist<T> 转换成 DataSet
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public static DataSet ConvertToDataSet<T>(IList<T> i_objlist)
        {
            DataSet ds = new DataSet();
            ds.Tables.Add(Convert.ConvertToDataTable(i_objlist));
            return ds;
        }

        /// <summary>
        /// 根据T创建DataTable
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static DataTable CreateDataTableByT<T>()
        {
            var dt = new DataTable(typeof(T).Name);            
            System.Reflection.PropertyInfo[] myPropertyInfo = typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
            SetDataTableColumn(typeof(T).Name, myPropertyInfo, dt);
            return dt;
        }
        
        //// <summary>
        /// Ilist<T> 转换成 DataTable
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public static DataTable ConvertToDataTable<T>(IList<T> i_objlist)
        {
            if (i_objlist == null || i_objlist.Count <= 0)
            {
                return null;
            }

            var dt = CreateDataTableByT<T>();
            System.Reflection.PropertyInfo[] myPropertyInfo = typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
            DataRow row;
            foreach (T t in i_objlist)
            {
                if (t == null)
                {
                    continue;
                }

                row = dt.NewRow();
                SetDataTableValue(t, myPropertyInfo, ref row);
                dt.Rows.Add(row);
            }
            return dt;
        }

        private static void SetDataTableValue<T>(T t, System.Reflection.PropertyInfo[] pis, ref DataRow row)
        {
            String ClassName = t.GetType().Name;
            foreach (PropertyInfo pi in pis)
            {
                String ColumnName = Functions.GetColumnName(ClassName, pi.Name);
                var DataType = System.Type.GetType(pi.PropertyType.ToString(),false);
                if (DataType == null)
                {
                    SetDataTableValue(pi.GetValue(t, null), pi.PropertyType.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance), ref row);
                    continue;
                }
                object o = pi.GetValue(t, null);
                if (o == null)
                {
                    o = DBNull.Value;
                }
                row[ColumnName] = o;
            }
        }

        public static void DataRowConvertToObject<T>(T t, DataRow drSource)
        {
            String ClassName = t.GetType().Name;
            PropertyInfo[] myPropertyInfos = t.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
            foreach (PropertyInfo pi in myPropertyInfos)
            {
                String ColumnName = Functions.GetColumnName(ClassName, pi.Name);

                var DataType = System.Type.GetType(pi.PropertyType.ToString(), false);
                if (DataType == null)
                {
                    DataRowConvertToObject(GetPropertyValue(ref t, pi), drSource);
                    continue;
                }
                if (drSource[ColumnName] == DBNull.Value)
                {
                    continue;
                }
                pi.SetValue(t, drSource[ColumnName], null);
            }
        }

        //目前只支持多对一
        public static void ObjectConvertToDataRow<T>(T t,ref DataRow drSource)
        {
            String ClassName = t.GetType().Name;
            PropertyInfo[] myPropertyInfos = t.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
            foreach (PropertyInfo pi in myPropertyInfos)
            {
                String ColumnName = Functions.GetColumnName(ClassName, pi.Name);
                object o = pi.GetValue(t, null);
                if (o == null)
                {
                    continue;
                }

                var DataType = System.Type.GetType(pi.PropertyType.ToString(), false);
                if (DataType == null)
                {
                    ObjectConvertToDataRow(o,ref drSource);
                    continue;
                }
                drSource[ColumnName] = o;
            }
        }

        private static object GetPropertyValue<T>(ref T tObject, PropertyInfo pi)
        {
            object o = pi.GetValue(tObject, null);
            if (o != null)
            {
                return o;
            }
            Assembly asm = Assembly.Load(pi.PropertyType.Namespace);
            o = asm.CreateInstance(pi.PropertyType.FullName);
            pi.SetValue(tObject, o, null);
            return o;             
        }


        private static void SetDataTableColumn(String ClassName,System.Reflection.PropertyInfo[] pis, DataTable dtColumn)
        {
            foreach (System.Reflection.PropertyInfo pi in pis)
            {
                if (pi == null)
                {
                    continue;
                }

                var DataType = System.Type.GetType(pi.PropertyType.ToString(),false);
                if (DataType == null)
                {
                    SetDataTableColumn(pi.PropertyType.Name,pi.PropertyType.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance), dtColumn);
                    continue;
                }
                if (dtColumn.Columns.Contains(Functions.GetColumnName(ClassName, pi.Name)))
                {
                    continue;
                }
                //DataTable不支持Nullable
                if (null != Nullable.GetUnderlyingType(DataType))
                {
                    DataType = Nullable.GetUnderlyingType(DataType);
                }
                
                dtColumn.Columns.Add(Functions.GetColumnName(ClassName, pi.Name), DataType);
            }
        }
    }
}
